/*
* ========== Copyright Header Begin ==========================================
* 
* OpenSPARC T1 Processor File: sparcv9native.S
* Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* 
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* 
* The above named program is distributed in the hope that it will be 
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
* 
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* 
* ========== Copyright Header End ============================================
*/
/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma	ident	"@(#)sparcv9native.S	1.22	06/03/05 SMI"

#include <sys/asm_linkage.h>
#include "assembly.h"


	/*
	 * Assembly support functions required by the simulator
	 */


	.section ".text"

	ENTRY(sim_atomic_add_32)
	ALTENTRY(sim_atomic_add_32_nv)
	ALTENTRY(sim_atomic_add_long)
	ALTENTRY(sim_atomic_add_long_nv)
	ld	[%o0], %o2
1:
	add	%o2, %o1, %o3
	cas	[%o0], %o2, %o3
	cmp	%o2, %o3
	bne,a,pn %icc, 1b
	ld	[%o0], %o2
	retl
	add	%o2, %o1, %o0		! return new value
	SET_SIZE(sim_atomic_add_32_nv)
	SET_SIZE(sim_atomic_add_32)
	SET_SIZE(sim_atomic_add_long_nv)
	SET_SIZE(sim_atomic_add_long)

		/*
		 * o0 = pointer to memory location
		 * o1 = value to compare with
		 * o2 = value to swap in if equal
		 * returns:
		 * o0 = original contents of memory location
		 */
	.global	host_ldstub
host_ldstub:
	ldstub	[%o0], %o2
	retl
	mov	%o2, %o0
	
		/*
		 * o0 = pointer to memory location
		 * o1 = value to compare with
		 * o2 = value to swap in if equal
		 * returns:
		 * o0 = original contents of memory location
		 */
	.global	host_cas32
host_cas32:
	cas	[%o0], %o1, %o2
	retl
	mov	%o2, %o0

	.global	host_cas64
host_cas64:
	casx	[%o0], %o1, %o2
	retl
	mov	%o2, %o0

	.global host_swap
host_swap:
	swap	[%o0], %o1
	retl
	mov	%o1, %o0


		/*
		 * Atomic load of 128 bits big endian into two 64bit registers.
		 * Have to do this kludge because SPARC doesnt provide a 128bit atomic
		 * fetch that executes at user level.
		 * I just hope the 64byte block load is atomic on all architectures.
		 * %o0 points to memory location (128 bit aligned).
		 * %o1 points to high 64bits of result register (big endian)
		 * %o2 points to low 64bits of result register (big endian)
		 */

#define	ASI_BLK_P	0xf0	/* VIS 1.0 block load from primary AS */

	.global host_atomic_get128be
host_atomic_get128be:
		/* align the memory address for a block load */
	andn	%o0, 0x3f, %o3
	ldda	[%o3]ASI_BLK_P, %f0
	and	%o0, 0x30, %o4		/* figure out which of the 4 128bit blocks we want */
	membar	#Sync			/* ensure the data is present */
_base:
	rd	%pc, %o0
	add	%o4, %o0, %o0
	jmpl	%o0 + (_xxword0 - _base), %g0
_xxword0:
	std	%f0, [ %o1 ]
	retl
	std	%f2, [ %o2 ]
	nop
_xxword1:
	std	%f4, [ %o1 ]
	retl
	std	%f6, [ %o2 ]
	nop
_xxword2:
	std	%f8, [ %o1 ]
	retl
	std	%f10, [ %o2 ]
	nop
_xxword3:
	std	%f12, [ %o1 ]
	retl
	std	%f14, [ %o2 ]
	nop







	/*
	 * Assembly version of certain simulator instruction implementations.
	 */










#define	ld_simm16( _Rxip, _offset, _Rdest )	\
	ldsh	[ _Rxip + _offset ], _Rdest		/* 1 instn only !! */

#define	ld_simm32( _Rxip, _offset, _Rdest )	\
	ldsw	[ _Rxip + _offset ], _Rdest		/* 1 instn only !! */

#define	ldx_ireg( _Rcpup, _Rxip, _offset, _Rdest, _Rscratch )	\
	lduh	[ _Rxip + _offset ], _Rscratch		NL\
	ldx	[ _Rcpup + _Rscratch ], _Rdest

#define	stx_ireg( _Rcpup, _Rxip, _offset, _Rval, _Rscratch )	\
	lduh	[ _Rxip + _offset ], _Rscratch		NL\
	stx	_Rval, [ _Rcpup + _Rscratch ]

#define	ld_fpreg( _ldt, _Rcpup, _Rxip, _Rfprp, _offset, _Rdest, _Rscratch )	\
	lduh	[ _Rxip + _offset ], _Rscratch				NL\
	_ldt	[ _Rfprp + _Rscratch ], _Rdest

#define	st_fpreg( _stt, _Rcpup, _Rxip, _Rfprp, _offset, _Rdest, _Rscratch )	\
	lduh	[ _Rxip + _offset ], _Rscratch				NL\
	_stt	_Rdest, [ _Rfprp + _Rscratch ]

	/*
	 * %o0 = simcpu_t *
	 * %o1 = xicache_instn_t *
	 * %g1 is used as a scratch register by these macros
	 */

#define	ldx_Rsrc1( _r )	ldx_ireg( %o0, %o1, XIC_INTREG_SRC1_OFFSET, _r, %g1 )
#define	ldx_Rsrc2( _r )	ldx_ireg( %o0, %o1, XIC_INTREG_SRC2_OFFSET, _r, %g1 )
#define	ld_Simm16( _r )	ld_simm16( %o1, XIC_SIMM16_OFFSET, _r )

#define	ld_BrOff32( _r )	ld_simm32( %o1, XIC_BROFF32_OFFSET, _r )

#define	ld_BrRegOff32( _r )	ld_simm32( %o1, XIC_BREGOFF32_OFFSET, _r )

#define	stx_Rdest( _r )	stx_ireg( %o0, %o1, XIC_INTREG_DEST_OFFSET, _r, %g1 )

#define	ldx_Rccr( _r )	ldx	[ %o0 + SIMCPU_v9CCR_OFFSET ], _r
#define	stx_Rccr( _r )	stx	_r, [ %o0 + SIMCPU_v9CCR_OFFSET ]

#define	ldx_Rpc( _r )	ldx	[ %o0 + SIMCPU_PC_OFFSET ], _r
#define	stx_Rpc( _r )	stx	_r, [ %o0 + SIMCPU_PC_OFFSET ]
#define	ldx_Rnpc( _r )	ldx	[ %o0 + SIMCPU_NPC_OFFSET ], _r
#define	stx_Rnpc( _r )	stx	_r, [ %o0 + SIMCPU_NPC_OFFSET ]


	/* FP support */

#define	ld_FPsrc1( _ldt, _r )	ld_fpreg( _ldt, %o0, %o1, %o0, XIC_FPREG_SRC1_OFFSET, _r, %g1 )
#define	ld_FPsrc2( _ldt, _r )	ld_fpreg( _ldt, %o0, %o1, %o0, XIC_FPREG_SRC2_OFFSET, _r, %g1 )
#define	st_FPdest( _stt, _r )	st_fpreg( _stt, %o0, %o1, %o0, XIC_FPREG_DEST_OFFSET, _r, %g1 )


#define	IMPL( _name )					\
							NL\
	.global decoded_impl_##_name			NL\
	.align	8					NL\
decoded_impl_##_name:



#define	ENDI			\
	ldx [ %o0 + SIMCPU_NPC_OFFSET ], %o1		NL\
	add	%o1, 4, %o2				NL\
	stx %o1, [ %o0 + SIMCPU_PC_OFFSET ]		NL\
	retl						NL\
	stx %o2, [ %o0 + SIMCPU_NPC_OFFSET ]		NL\
	ENDINSTN

#define	ENDINSTN	/* nada */
	


	/*
	 * For executing floating point operations on SPARC ..
	 * .. specifically SPARC on SPARC we use the FSR for the
	 * cpu being emulated, but disable all floating point traps.
	 * Then we test whether an exception has occurred after the
	 * instruction execution, and update the simulated FSR
	 * accordingly, then finally signal a trap if the simulated
	 * machine actually desired one.
	 *
	 * the simcpu_t simualted registers are used as follows:
	 *	v9_fsr_ctrl holds the SPARC fsr control bits ..
	 * for condition codes, rounding etc. The execution results
	 * (errors and accumulated errors) are held in the the
	 * v9_fsr_exe pseudo register, and the trap enable bits
	 * (TEM) are held in the v9_fsr_tem pseudo reg.
	 *
	 * Note: we have to use the simcpu_t scratch64 value because we
	 * can't get the bloody fsr value out of the cpu without using a
	 * store instruction. This prob. should be per exec_thread, but
	 * its harder to get at than per simcpu in here.
	 */



#define	FPOP_setup_fsr					\
	ldx	[ %o0 + SIMCPU_v9FSR_CTRL_OFFSET ], %o4	NL\
	set	0xff, %o3				NL\
	sllx	%o3, 30, %o3 /* FCC[321] + RD mask */	NL\
	or	%o3, (3 << 10), %o3 /* | FCC0 mask */	NL\
	and	%o4, %o3, %o4				NL\
	stx	%o4, [ %o0 + SIMCPU_SCRATCH64_OFFSET ]	NL\
	ldx	[ %o0 + SIMCPU_SCRATCH64_OFFSET ], %fsr	NL\
	ldx	[ %o0 + SIMCPU_v9GSR_CTRL_OFFSET ], %o4	NL\
	wr	%o4, %gsr

#ifdef FP_DECODE_DISABLED
#define	FPOP_fpu_on_check
#else /* FP_DECODE_DISABLED */
#define	FPOP_fpu_on_check				\
	ldx	[ %o0 + SIMCPU_SPECIFICP_OFFSET ], %o4	NL\
	ld	[ %o4 + SPARCV9_FPU_ON_OFFSET ], %o4	NL\
	brz	%o4, sparcv9_deliver_fp_disabled_exception	NL\
	nop
#endif /* FP_DECODE_DISABLED */

#define	FPOP_no_setup					\
	FPOP_fpu_on_check

#define	FPOP_setup					\
	FPOP_fpu_on_check				NL\
	FPOP_setup_fsr

#define	FPOP_rrr( _ld1t, _ld2t, _stt, _fpop )		\
	FPOP_setup					NL\
	ld_FPsrc1( _ld1t, %f0 )				NL\
	ld_FPsrc2( _ld2t, %f4 )				NL\
	_fpop	%f0, %f4, %f8				NL\
	FPOP_cleanup					NL\
	st_FPdest( _stt, %f8 )				NL\
	FPOP_ENDI

#define	FPOP_rr( _ld1t, _stt, _fpop )			\
	FPOP_setup					NL\
	ld_FPsrc1( _ld1t, %f0 )				NL\
	_fpop	%f0, %f8				NL\
	FPOP_cleanup					NL\
	st_FPdest( _stt, %f8 )				NL\
	FPOP_ENDI

#define	FPOP_cmp( _ldt, _fpop, _fcc )		\
	FPOP_setup					NL\
	ld_FPsrc1( _ldt, %f0 )				NL\
	ld_FPsrc2( _ldt, %f4 )				NL\
	_fpop	%_fcc, %f0, %f4				NL\
	FPOP_cleanup					NL\
	FPOP_save_fcc					NL\
	FPOP_ENDI

/* FPOP_save_fcc assumes FPOP_cleanup stored %fsr in scratch */
#define	FPOP_save_fcc					\
	ldx	[ %o0 + SIMCPU_SCRATCH64_OFFSET ], %o4	NL\
	set	0x3f, %o3				NL\
	sllx	%o3, 32, %o3 /* FCC[321] mask */	NL\
	or	%o3, (3 << 10), %o3 /* | FCC0 mask */	NL\
	ldx	[ %o0 + SIMCPU_v9FSR_CTRL_OFFSET ], %o2	NL\
	andn	%o2, %o3, %o2				NL\
	and	%o4, %o3, %o4				NL\
	or	%o2, %o4, %o2				NL\
	stx	%o2, [ %o0 + SIMCPU_v9FSR_CTRL_OFFSET ]


		/*
		 * Since we're running as a user process, we're not
		 * going to see anything here other than ieee754 exceptions
		 *
		 * But these have to be handled carefully, since the simulated FSR
		 * configuration may require that a proper exception is generated
		 * ... 
		 * annoyingly we have to save the fsr somewhere in order to get access to
		 * the execution results - we use a per-cpu scratch area so we avoid MT conflicts
		 *
		 * So retrieve the FSR, stash it back into ctrl sans error bits
		 * (tem bits should still be zero).
		 * Then, look for errors from the last executed instrucion .. if none, then
		 * do nothing. If some then accumulate or generate a trap as necessary.
		 */

	/* Must not modify %o0 or %o1 */
#define	FPOP_cleanup					\
	stx %fsr, [ %o0 + SIMCPU_SCRATCH64_OFFSET ]	NL\
	ldx [ %o0 + SIMCPU_SCRATCH64_OFFSET ], %o4	NL\
	/* must clear cexec field if no exceptions */	NL\
	ldx	[ %o0 + SIMCPU_v9FSR_EXC_OFFSET ], %o3	NL\
	and	%o3, 0x1f<<5, %o3			NL\
	stx	%o3, [ %o0 + SIMCPU_v9FSR_EXC_OFFSET ]	NL\
	andcc %o4, 0x1f, %o2				NL\
	bne,a,pt %xcc, sparcv9_fsr_exception_update	NL\
	rd	%pc, %o5				NL\
	/* fall through to the update part of the instruction */

#define	FPOP_ENDI					\
	ENDI
	

		/*
		 * Hand off routine for floating point closure
		 * If any IEEE exception occurred, we need now to check and see if the simulated
		 * FSR required a trap to be generated, or the error to be accumulated.
		 * NOTE: error is not accumulated if a trap is to be delivered.
		 */

	.section ".text"
	.align 8
sparcv9_fsr_exception_update:
	ldx	[ %o0 + SIMCPU_v9FSR_TEM_OFFSET ], %o3
	ldx	[ %o0 + SIMCPU_v9FSR_CTRL_OFFSET ], %o4
	srlx	%o4, 14, %o4	/* FTT field - no trap if non-zero */
	and	%o4, 7, %o4
	movrnz	%o4, %g0, %o3
	andcc	%o2, %o3, %g0
			/* OK build the EXC group ... */
	sllx	%o2, 5, %o3
			/* clear the accumulation if trap to be delivered */
	movne	%xcc, %g0, %o3
	ldx	[ %o0 + SIMCPU_v9FSR_EXC_OFFSET ], %o4
			/* build error and accum bits */
	or	%o2, %o3, %o2
			/* mask out previous accum bits */
	and	%o4, 0x1f<<5, %o4
			/* combine new error and old accum bits */
	or	%o2, %o4, %o2
			/* update the execution FSR state */
	stx	%o2, [ %o0 + SIMCPU_v9FSR_EXC_OFFSET ]
			/* now that the status is updated, branch into the
			 * C function to deliver the IEEE trap if appropriate
			 */
	bne,pn	%xcc, sparcv9_deliver_ieee_exception
	nop
	jmp	%o5 + 4	/* finish instruction */
	nop



		/*
		 * instruction targets
		 * implemented in assembly language to improve performance on
		 * certain host machines.
		 *
		 * This file is for a sparcv9 host.
		 */

	.section ".text"
	.align 8

		/* Args are: %o0 = simcpu_t*, %o1 = xicache_instn_t * */



		/*
		 * Sparc v9 add and substract instructions
		 */

IMPL( sparcv9_add_co_imm )
	ba internal_add_co;
	ld_Simm16(%o3)

IMPL( sparcv9_add_co_rrr )
	ldx_Rsrc2(%o3)
internal_add_co:
	ldx_Rsrc1(%o2)
	addcc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




IMPL( sparcv9_add_co_imm_rd0 )
	ba internal_add_co_rd0;
	ld_Simm16(%o3)

IMPL( sparcv9_add_co_rrr_rd0 )
	ldx_Rsrc2(%o3)
internal_add_co_rd0:
	ldx_Rsrc1(%o2)
	addcc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




IMPL( sparcv9_add_ci_imm )
	ba internal_add_ci;
	ld_Simm16(%o3)

IMPL( sparcv9_add_ci_rrr )
	ldx_Rsrc2(%o3)
internal_add_ci:
	ldx_Rccr(%o4)
	wr	%o4, %ccr
	ldx_Rsrc1(%o2)
	addc	%o2, %o3, %o2
	stx_Rdest(%o2)
	ENDI




IMPL( sparcv9_add_cico_imm )
	ba internal_add_cico;
	ld_Simm16(%o3)

IMPL( sparcv9_add_cico_rrr )
	ldx_Rsrc2(%o3)
internal_add_cico:
	ldx_Rccr(%o4)
	wr	%o4, %ccr
	ldx_Rsrc1(%o2)
	addccc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




IMPL( sparcv9_add_cico_imm_rd0 )
	ba internal_add_cico_rd0;
	ld_Simm16(%o3)

IMPL( sparcv9_add_cico_rrr_rd0 )
	ldx_Rsrc2(%o3)
internal_add_cico_rd0:
	ldx_Rccr(%o4)
	wr	%o4, %ccr
	ldx_Rsrc1(%o2)
	addccc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI







IMPL( sparcv9_sub_co_imm )
	ba internal_sub_co;
	ld_Simm16(%o3)

IMPL( sparcv9_sub_co_rrr )
	ldx_Rsrc2(%o3)
internal_sub_co:
	ldx_Rsrc1(%o2)
	subcc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




IMPL( sparcv9_sub_co_imm_rd0 )
	ba internal_sub_co_rd0;
	ld_Simm16(%o3)

IMPL( sparcv9_sub_co_rrr_rd0 )
	ldx_Rsrc2(%o3)
internal_sub_co_rd0:
	ldx_Rsrc1(%o2)
	subcc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




IMPL( sparcv9_sub_ci_imm )
	ba internal_sub_ci;
	ld_Simm16(%o3)

IMPL( sparcv9_sub_ci_rrr )
	ldx_Rsrc2(%o3)
internal_sub_ci:
	ldx_Rccr(%o4)
	wr	%o4, %ccr
	ldx_Rsrc1(%o2)
	subc	%o2, %o3, %o2
	stx_Rdest(%o2)
	ENDI




IMPL( sparcv9_sub_cico_imm )
	ba internal_sub_cico;
	ld_Simm16(%o3)

IMPL( sparcv9_sub_cico_rrr )
	ldx_Rsrc2(%o3)
internal_sub_cico:
	ldx_Rccr(%o4)
	wr	%o4, %ccr
	ldx_Rsrc1(%o2)
	subccc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




IMPL( sparcv9_sub_cico_imm_rd0 )
	ba internal_sub_cico_rd0;
	ld_Simm16(%o3)

IMPL( sparcv9_sub_cico_rrr_rd0 )
	ldx_Rsrc2(%o3)
internal_sub_cico_rd0:
	ldx_Rccr(%o4)
	wr	%o4, %ccr
	ldx_Rsrc1(%o2)
	subccc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




	/*
	 * Logic CC instructions ...
	 */

IMPL( sparcv9_and_cc_imm )
	ba internal_and_cc;
	ld_Simm16(%o3)

IMPL( sparcv9_and_cc_rrr )
	ldx_Rsrc2(%o3)
internal_and_cc:
	ldx_Rsrc1(%o2)
	andcc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




IMPL( sparcv9_and_cc_imm_rd0 )
	ba internal_and_cc_rd0;
	ld_Simm16(%o3)

IMPL( sparcv9_and_cc_rrr_rd0 )
	ldx_Rsrc2(%o3)
internal_and_cc_rd0:
	ldx_Rsrc1(%o2)
	andcc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




	/*  sparcv9_andn_cc_imm  - synthesysed by inverting imm for andcc */

IMPL( sparcv9_andn_cc_rrr )
	ldx_Rsrc2(%o3)
	ldx_Rsrc1(%o2)
	andncc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




	/*  sparcv9_andn_cc_imm_rd0 - synthesysed by inverting imm for andcc */

IMPL( sparcv9_andn_cc_rrr_rd0 )
	ldx_Rsrc2(%o3)
	ldx_Rsrc1(%o2)
	andncc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI



IMPL( sparcv9_or_cc_imm )
	ba internal_or_cc;
	ld_Simm16(%o3)

IMPL( sparcv9_or_cc_rrr )
	ldx_Rsrc2(%o3)
internal_or_cc:
	ldx_Rsrc1(%o2)
	orcc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




IMPL( sparcv9_or_cc_imm_rd0 )
	ba internal_or_cc_rd0;
	ld_Simm16(%o3)

IMPL( sparcv9_or_cc_rrr_rd0 )
	ldx_Rsrc2(%o3)
internal_or_cc_rd0:
	ldx_Rsrc1(%o2)
	orcc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI





	/* sparcv9_orn_cc_imm	- synth by inverting imm field for orcc */

IMPL( sparcv9_orn_cc_rrr )
	ldx_Rsrc2(%o3)
	ldx_Rsrc1(%o2)
	orncc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




	/* sparcv9_orn_cc_imm_rd0 - synth by inverting imm field for orcc */

IMPL( sparcv9_orn_cc_rrr_rd0 )
	ldx_Rsrc2(%o3)
	ldx_Rsrc1(%o2)
	orncc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI





IMPL( sparcv9_xor_cc_imm )
	ba internal_xor_cc;
	ld_Simm16(%o3)

IMPL( sparcv9_xor_cc_rrr )
	ldx_Rsrc2(%o3)
internal_xor_cc:
	ldx_Rsrc1(%o2)
	xorcc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




IMPL( sparcv9_xor_cc_imm_rd0 )
	ba internal_xor_cc_rd0;
	ld_Simm16(%o3)

IMPL( sparcv9_xor_cc_rrr_rd0 )
	ldx_Rsrc2(%o3)
internal_xor_cc_rd0:
	ldx_Rsrc1(%o2)
	xorcc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI





	/* sparcv9_xnor_cc_imm - can synth by ~imm using orcc imm */

IMPL( sparcv9_xnor_cc_rrr )
	ldx_Rsrc2(%o3)
	ldx_Rsrc1(%o2)
	xnorcc	%o2, %o3, %o2
	stx_Rdest(%o2)
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI




	/* sparcv9_xnor_cc_imm_rd0  - can synth by ~imm using xorcc imm */

IMPL( sparcv9_xnor_cc_rrr_rd0 )
	ldx_Rsrc2(%o3)
	ldx_Rsrc1(%o2)
	xnorcc	%o2, %o3, %g0
	rd	%ccr, %o3
	stx_Rccr(%o3)
	ENDI



#if 0 /* { */
	IMPL( sparcv9_udivx_rrr )
		ldx_Rsrc2(%o3)
		ldx_Rsrc1(%o2)
		udivx	%o2, %o3, %o2
		stx_Rdest(%o2)
		ENDI
#endif /* } */



	/*
	 * Branch instructions change the value of npc
	 * Could encode a mask into the xi immediate, but that would
	 * be slow to extract, and leave us with a less than useful
	 * immediate field.
	 */

	/* delay slot:
	 *	always executed - IF a branch IS taken
	 *	annulled - if a bit set and branch IS NOT taken
	 */

	/* Sparc branches are bloody awful - delay slots plus mutiple
	 * condition varients ...
	 *
	 *	X: br	Y
	 *	   br	Z
	 *
	 *	Y: slot instn
	 *
	 *	Z:
	 *
	 * ... instn @X executes instn @Y, but then X+4 in DS of X causes branch to Z
	 */


	/*
	 * Policy
		annul:
			not taken:			taken:
			pc = oldnpc+4			pc = oldnpc
			npc = oldnpc + 8;		npc = target

		no annul:
			pc = npc
			npc = target | npc + 4;

	 */

	

#define	BRANCH( _opc, _cc )						\
	ldx_Rccr (%o2)									NL\
	wr	%o2, %ccr								NL\
	ldx_Rpc	(%o3)									NL\
	ldx_Rnpc(%o4)									NL\
	ld_BrOff32(%o5)									NL\
	stx_Rpc	(%o4)									NL\
	add	%o3, %o5, %o5		/* branch target */				NL\
	add	%o4, 4, %o4		/* npc + 4 */					NL\
	mov##_opc	_cc, %o5, %o4	/* overwrite npc if branch taken */	NL\
	retl										NL\
	stx_Rnpc(%o4)


#define	BRANCH_an( _opc, _cc )						\
	ldx_Rccr (%o2)									NL\
	wr	%o2, %ccr								NL\
	ldx_Rpc	(%o3)									NL\
	ldx_Rnpc(%o4)									NL\
	ld_BrOff32(%o2)									NL\
	add	%o3, %o2, %o3		/* branch target */				NL\
	add	%o4, 4, %o5		/* oldnpc + 4 */				NL\
	add	%o4, 8, %g1		/* oldnpc + 8 */				NL\
	mov##_opc	_cc, %o4, %o5	/* overwrite pc if branch taken */	NL\
	mov##_opc	_cc, %o3, %g1	/* overwrite npc if branch taken */	NL\
	stx_Rpc	(%o5)			/* no annul ds not squashed */			NL\
	retl										NL\
	stx_Rnpc(%g1)


	/* There has to be a better way than to ennunciate every instruction form !! */

	/* icc version */

IMPL( sparcv9_bne_icc )
	BRANCH( ne, %icc )
	ENDINSTN

IMPL( sparcv9_be_icc )
	BRANCH( e, %icc )
	ENDINSTN

IMPL( sparcv9_bg_icc )
	BRANCH( g, %icc )
	ENDINSTN

IMPL( sparcv9_ble_icc )
	BRANCH( le, %icc )
	ENDINSTN

IMPL( sparcv9_bge_icc )
	BRANCH( ge, %icc )
	ENDINSTN

IMPL( sparcv9_bl_icc )
	BRANCH( l, %icc )
	ENDINSTN

IMPL( sparcv9_bgu_icc )
	BRANCH( gu, %icc )
	ENDINSTN

IMPL( sparcv9_bleu_icc )
	BRANCH( leu, %icc )
	ENDINSTN

IMPL( sparcv9_bcc_icc )
	BRANCH( cc, %icc )
	ENDINSTN

IMPL( sparcv9_bcs_icc )
	BRANCH( cs, %icc )
	ENDINSTN

IMPL( sparcv9_bpos_icc )
	BRANCH( pos, %icc )
	ENDINSTN

IMPL( sparcv9_bneg_icc )
	BRANCH( neg, %icc )
	ENDINSTN

IMPL( sparcv9_bvc_icc )
	BRANCH( vc, %icc )
	ENDINSTN

IMPL( sparcv9_bvs_icc )
	BRANCH( vs, %icc )
	ENDINSTN


	/* xcc versions */

IMPL( sparcv9_bne_xcc )
	BRANCH( ne, %xcc )
	ENDINSTN

IMPL( sparcv9_be_xcc )
	BRANCH( e, %xcc )
	ENDINSTN

IMPL( sparcv9_bg_xcc )
	BRANCH( g, %xcc )
	ENDINSTN

IMPL( sparcv9_ble_xcc )
	BRANCH( le, %xcc )
	ENDINSTN

IMPL( sparcv9_bge_xcc )
	BRANCH( ge, %xcc )
	ENDINSTN

IMPL( sparcv9_bl_xcc )
	BRANCH( l, %xcc )
	ENDINSTN

IMPL( sparcv9_bgu_xcc )
	BRANCH( gu, %xcc )
	ENDINSTN

IMPL( sparcv9_bleu_xcc )
	BRANCH( leu, %xcc )
	ENDINSTN

IMPL( sparcv9_bcc_xcc )
	BRANCH( cc, %xcc )
	ENDINSTN

IMPL( sparcv9_bcs_xcc )
	BRANCH( cs, %xcc )
	ENDINSTN

IMPL( sparcv9_bpos_xcc )
	BRANCH( pos, %xcc )
	ENDINSTN

IMPL( sparcv9_bneg_xcc )
	BRANCH( neg, %xcc )
	ENDINSTN

IMPL( sparcv9_bvc_xcc )
	BRANCH( vc, %xcc )
	ENDINSTN

IMPL( sparcv9_bvs_xcc )
	BRANCH( vs, %xcc )
	ENDINSTN




		/*
		 * Annulled delay slot versions !!
		 */


	/* icc version */

IMPL( sparcv9_bne_icc_an )
	BRANCH_an( ne, %icc )
	ENDINSTN

IMPL( sparcv9_be_icc_an )
	BRANCH_an( e, %icc )
	ENDINSTN

IMPL( sparcv9_bg_icc_an )
	BRANCH_an( g, %icc )
	ENDINSTN

IMPL( sparcv9_ble_icc_an )
	BRANCH_an( le, %icc )
	ENDINSTN

IMPL( sparcv9_bge_icc_an )
	BRANCH_an( ge, %icc )
	ENDINSTN

IMPL( sparcv9_bl_icc_an )
	BRANCH_an( l, %icc )
	ENDINSTN

IMPL( sparcv9_bgu_icc_an )
	BRANCH_an( gu, %icc )
	ENDINSTN

IMPL( sparcv9_bleu_icc_an )
	BRANCH_an( leu, %icc )
	ENDINSTN

IMPL( sparcv9_bcc_icc_an )
	BRANCH_an( cc, %icc )
	ENDINSTN

IMPL( sparcv9_bcs_icc_an )
	BRANCH_an( cs, %icc )
	ENDINSTN

IMPL( sparcv9_bpos_icc_an )
	BRANCH_an( pos, %icc )
	ENDINSTN

IMPL( sparcv9_bneg_icc_an )
	BRANCH_an( neg, %icc )
	ENDINSTN

IMPL( sparcv9_bvc_icc_an )
	BRANCH_an( vc, %icc )
	ENDINSTN

IMPL( sparcv9_bvs_icc_an )
	BRANCH_an( vs, %icc )
	ENDINSTN


	/* xcc versions */

IMPL( sparcv9_bne_xcc_an )
	BRANCH_an( ne, %xcc )
	ENDINSTN

IMPL( sparcv9_be_xcc_an )
	BRANCH_an( e, %xcc )
	ENDINSTN

IMPL( sparcv9_bg_xcc_an )
	BRANCH_an( g, %xcc )
	ENDINSTN

IMPL( sparcv9_ble_xcc_an )
	BRANCH_an( le, %xcc )
	ENDINSTN

IMPL( sparcv9_bge_xcc_an )
	BRANCH_an( ge, %xcc )
	ENDINSTN

IMPL( sparcv9_bl_xcc_an )
	BRANCH_an( l, %xcc )
	ENDINSTN

IMPL( sparcv9_bgu_xcc_an )
	BRANCH_an( gu, %xcc )
	ENDINSTN

IMPL( sparcv9_bleu_xcc_an )
	BRANCH_an( leu, %xcc )
	ENDINSTN

IMPL( sparcv9_bcc_xcc_an )
	BRANCH_an( cc, %xcc )
	ENDINSTN

IMPL( sparcv9_bcs_xcc_an )
	BRANCH_an( cs, %xcc )
	ENDINSTN

IMPL( sparcv9_bpos_xcc_an )
	BRANCH_an( pos, %xcc )
	ENDINSTN

IMPL( sparcv9_bneg_xcc_an )
	BRANCH_an( neg, %xcc )
	ENDINSTN

IMPL( sparcv9_bvc_xcc_an )
	BRANCH_an( vc, %xcc )
	ENDINSTN

IMPL( sparcv9_bvs_xcc_an )
	BRANCH_an( vs, %xcc )
	ENDINSTN


#undef	BRANCH
#undef	BRANCH_an


	/*
	 * versions for the branch on register value operations
	 */



	/*
	 * Policy
		no annul:
			pc = npc
			npc = target | npc + 4;

		annul:
			not taken:			taken:
			pc = oldnpc+4			pc = oldnpc
			npc = oldnpc + 8;		npc = target

	 */

	


#define	BRANCH( _opc )								\
	ldx_Rsrc1(%o2)									NL\
	ldx_Rpc	(%o3)									NL\
	ldx_Rnpc(%o4)									NL\
	ld_BrRegOff32(%o5)								NL\
	stx_Rpc	(%o4)			/* pc = npc */					NL\
	add	%o3, %o5, %o5		/* branch target */				NL\
	add	%o4, 4, %o4		/* npc + 4 */					NL\
	movr##_opc %o2, %o5, %o4	/* overwrite npc if branch taken */		NL\
	retl										NL\
	stx_Rnpc(%o4)


#define	BRANCH_an( _opc )						\
	ldx_Rsrc1(%o2)									NL\
	ldx_Rpc	(%o3)									NL\
	ldx_Rnpc(%o4)									NL\
	add	%o4, 4, %o5		/* oldnpc + 4 */				NL\
	movr##_opc	%o2, %o4, %o5	/* overwrite pc if branch taken */		NL\
	stx_Rpc	(%o5)			/* no annul ds not squashed */			NL\
	ld_BrRegOff32(%o5)								NL\
	add	%o3, %o5, %o3		/* branch target */				NL\
	add	%o4, 8, %o5		/* oldnpc + 8 */				NL\
	movr##_opc	%o2, %o3, %o5	/* overwrite npc if branch taken */		NL\
	retl										NL\
	stx_Rnpc(%o5)


IMPL( sparcv9_brz )
	BRANCH( z )
	ENDINSTN

IMPL( sparcv9_brlez )
	BRANCH( lez )
	ENDINSTN

IMPL( sparcv9_brlz )
	BRANCH( lz )
	ENDINSTN

IMPL( sparcv9_brnz )
	BRANCH( nz )
	ENDINSTN

IMPL( sparcv9_brgz )
	BRANCH( gz )
	ENDINSTN

IMPL( sparcv9_brgez )
	BRANCH( gez )
	ENDINSTN

IMPL( sparcv9_brz_an )
	BRANCH_an( z )
	ENDINSTN

IMPL( sparcv9_brlez_an )
	BRANCH_an( lez )
	ENDINSTN

IMPL( sparcv9_brlz_an )
	BRANCH_an( lz )
	ENDINSTN

IMPL( sparcv9_brnz_an )
	BRANCH_an( nz )
	ENDINSTN

IMPL( sparcv9_brgz_an )
	BRANCH_an( gz )
	ENDINSTN

IMPL( sparcv9_brgez_an )
	BRANCH_an( gez )
	ENDINSTN




	/*
	 * Floating point functions
	 *
	 *  ( src op src -> dest )
	 */

IMPL( sparcv9_fadds )
	FPOP_rrr( ld, ld, st, fadds )
	ENDINSTN

IMPL( sparcv9_faddd )
	FPOP_rrr( ldd, ldd, std, faddd )
	ENDINSTN

IMPL( sparcv9_faddq )
	FPOP_rrr( ldq, ldq, stq, faddq )
	ENDINSTN


IMPL( sparcv9_fsubs )
	FPOP_rrr( ld, ld, st, fsubs )
	ENDINSTN

IMPL( sparcv9_fsubd )
	FPOP_rrr( ldd, ldd, std, fsubd )
	ENDINSTN

IMPL( sparcv9_fsubq )
	FPOP_rrr( ldq, ldq, stq, fsubq )
	ENDINSTN


IMPL( sparcv9_fmuls )
	FPOP_rrr( ld, ld, st, fmuls )
	ENDINSTN

IMPL( sparcv9_fmuld )
	FPOP_rrr( ldd, ldd, std, fmuld )
	ENDINSTN

IMPL( sparcv9_fmulq )
	FPOP_rrr( ldq, ldq, stq, fmulq )
	ENDINSTN


IMPL( sparcv9_fdivs )
	FPOP_rrr( ld, ld, st, fdivs )
	ENDINSTN

IMPL( sparcv9_fdivd )
	FPOP_rrr( ldd, ldd, std, fdivd )
	ENDINSTN

IMPL( sparcv9_fdivq )
	FPOP_rrr( ldq, ldq, stq, fdivq )
	ENDINSTN


IMPL( sparcv9_fsmuld )
	FPOP_rrr( ld, ld, std, fsmuld )
	ENDINSTN

IMPL( sparcv9_fdmulq )
	FPOP_rrr( ldd, ldd, stq, fdmulq )
	ENDINSTN




	/*
	 * Floating point functions
	 *
	 *  ( src op -> dest )
	 */

IMPL( sparcv9_fstod )
	FPOP_rr( ld, std, fstod )
	ENDINSTN

IMPL( sparcv9_fstoq )
	FPOP_rr( ld, stq, fstoq )
	ENDINSTN


IMPL( sparcv9_fdtos )
	FPOP_rr( ldd, st, fdtos )
	ENDINSTN

IMPL( sparcv9_fdtoq )
	FPOP_rr( ldd, stq, fdtoq )
	ENDINSTN


IMPL( sparcv9_fqtos )
	FPOP_rr( ldq, st, fqtos )
	ENDINSTN

IMPL( sparcv9_fqtod )
	FPOP_rr( ldq, std, fqtod )
	ENDINSTN


IMPL( sparcv9_fsqrts )
	FPOP_rr( ld, st, fsqrts )
	ENDINSTN

IMPL( sparcv9_fsqrtd )
	FPOP_rr( ldd, std, fsqrtd )
	ENDINSTN

IMPL( sparcv9_fsqrtq )
	FPOP_rr( ldq, stq, fsqrtq )
	ENDINSTN


	/*
	 * SPARC integer<->floating point conversion instructions.
	 */

IMPL( sparcv9_fstoi )
	FPOP_rr( ld, st, fstoi )
	ENDINSTN

IMPL( sparcv9_fitos )
	FPOP_rr( ld, st, fitos )
	ENDINSTN

IMPL( sparcv9_fdtoi )
	FPOP_rr( ldd, st, fdtoi )
	ENDINSTN

IMPL( sparcv9_fitod )
	FPOP_rr( ld, std, fitod )
	ENDINSTN

IMPL( sparcv9_fstox )
	FPOP_rr( ld, std, fstox )
	ENDINSTN

IMPL( sparcv9_fxtos )
	FPOP_rr( ldd, st, fxtos )
	ENDINSTN

IMPL( sparcv9_fdtox )
	FPOP_rr( ldd, std, fdtox )
	ENDINSTN

IMPL( sparcv9_fxtod )
	FPOP_rr( ldd, std, fxtod )
	ENDINSTN


	/*
	 * SPARC floating point compares
	 */

IMPL( sparcv9_fcmps_fcc0 )
	FPOP_cmp( ld, fcmps, fcc0 )
	ENDINSTN

IMPL( sparcv9_fcmps_fcc1 )
	FPOP_cmp( ld, fcmps, fcc1 )
	ENDINSTN

IMPL( sparcv9_fcmps_fcc2 )
	FPOP_cmp( ld, fcmps, fcc2 )
	ENDINSTN

IMPL( sparcv9_fcmps_fcc3 )
	FPOP_cmp( ld, fcmps, fcc3 )
	ENDINSTN

IMPL( sparcv9_fcmpd_fcc0 )
	FPOP_cmp( ldd, fcmpd, fcc0 )
	ENDINSTN

IMPL( sparcv9_fcmpd_fcc1 )
	FPOP_cmp( ldd, fcmpd, fcc1 )
	ENDINSTN

IMPL( sparcv9_fcmpd_fcc2 )
	FPOP_cmp( ldd, fcmpd, fcc2 )
	ENDINSTN

IMPL( sparcv9_fcmpd_fcc3 )
	FPOP_cmp( ldd, fcmpd, fcc3 )
	ENDINSTN

IMPL( sparcv9_fcmpes_fcc0 )
	FPOP_cmp( ld, fcmpes, fcc0 )
	ENDINSTN

IMPL( sparcv9_fcmpes_fcc1 )
	FPOP_cmp( ld, fcmpes, fcc1 )
	ENDINSTN

IMPL( sparcv9_fcmpes_fcc2 )
	FPOP_cmp( ld, fcmpes, fcc2 )
	ENDINSTN

IMPL( sparcv9_fcmpes_fcc3 )
	FPOP_cmp( ld, fcmpes, fcc3 )
	ENDINSTN

IMPL( sparcv9_fcmped_fcc0 )
	FPOP_cmp( ldd, fcmped, fcc0 )
	ENDINSTN

IMPL( sparcv9_fcmped_fcc1 )
	FPOP_cmp( ldd, fcmped, fcc1 )
	ENDINSTN

IMPL( sparcv9_fcmped_fcc2 )
	FPOP_cmp( ldd, fcmped, fcc2 )
	ENDINSTN

IMPL( sparcv9_fcmped_fcc3 )
	FPOP_cmp( ldd, fcmped, fcc3 )
	ENDINSTN




	/*
	 * SPARC floating point ops which cannot trap or use the FSR
	 */

IMPL( sparcv9_fmovs )
	FPOP_no_setup
	ld_FPsrc1( ld, %f0 )
	fmovs	%f0, %f8
	st_FPdest( st, %f8 )
	ENDI

IMPL( sparcv9_fmovd )
	FPOP_no_setup
	ld_FPsrc1( ldd, %f0 )
	fmovd	%f0, %f8
	st_FPdest( std, %f8 )
	ENDI

IMPL( sparcv9_fmovq )
	FPOP_no_setup
	ld_FPsrc1( ldq, %f0 )
	fmovq	%f0, %f8
	st_FPdest( stq, %f8 )
	ENDI

IMPL( sparcv9_fnegs )
	FPOP_no_setup
	ld_FPsrc1( ld, %f0 )
	fnegs	%f0, %f8
	st_FPdest( st, %f8 )
	ENDI

IMPL( sparcv9_fnegd )
	FPOP_no_setup
	ld_FPsrc1( ldd, %f0 )
	fnegd	%f0, %f8
	st_FPdest( std, %f8 )
	ENDI

IMPL( sparcv9_fnegq )
	FPOP_no_setup
	ld_FPsrc1( ldq, %f0 )
	fnegq	%f0, %f8
	st_FPdest( stq, %f8 )
	ENDI

IMPL( sparcv9_fabss )
	FPOP_no_setup
	ld_FPsrc1( ld, %f0 )
	fabss	%f0, %f8
	st_FPdest( st, %f8 )
	ENDI

IMPL( sparcv9_fabsd )
	FPOP_no_setup
	ld_FPsrc1( ldd, %f0 )
	fabsd	%f0, %f8
	st_FPdest( std, %f8 )
	ENDI

IMPL( sparcv9_fabsq )
	FPOP_no_setup
	ld_FPsrc1( ldq, %f0 )
	fabsq	%f0, %f8
	st_FPdest( stq, %f8 )
	ENDI

IMPL( sparcv9_fones )
	FPOP_no_setup
	fones	%f0
	st_FPdest( st, %f0 )
	ENDI

IMPL( sparcv9_foned )
	FPOP_no_setup
	fone	%f0
	st_FPdest( std, %f0 )
	ENDI


IMPL( sparcv9_fzeros )
	FPOP_no_setup
	fzeros	%f0
	st_FPdest( st, %f0 )
	ENDI

IMPL( sparcv9_fzerod )
	FPOP_no_setup
	fzero	%f0
	st_FPdest( std, %f0 )
	ENDI
